﻿Namespace EIB.Bus
    Public NotInheritable Class EIBBusData_FrameLBusMonData
        Inherits EIBBusData_FrameBase

        Private _Status As Byte = Nothing
        Private _Status_FrameError As Boolean = Nothing
        Private _Status_BitError As Boolean = Nothing
        Private _Status_ParityError As Boolean = Nothing
        Private _Status_OverflowFlag As Boolean = Nothing
        Private _Status_LostFlag As Boolean = Nothing
        Private _Status_SequenceNr As Byte = Nothing

        Private _TimeStamp As UInt16 = Nothing

        Private _Control As Byte = Nothing
        Private _RepeatFlag As BusData.EIBBusData_FrameRepeatFlag = Nothing
        Private _Priority As BusData.EIBBusData_FramePriority = Nothing

        Private _SourceAddress As Addressing.EIBPhysicalAddress = Nothing
        Private _DestinationAddress As Addressing.EIBAddress = Nothing

        Private _NCPI As Byte = Nothing
        Private _DestinationType As BusData.EIBBusData_FrameDestinationType = Nothing
        Private _Routing As Byte = Nothing
        Private _DataLength As Byte = Nothing

        Private _TCPI As Byte = Nothing
        Private _ACPI As BusData.EIBBusData_FrameACPI_L_Data_Type = Nothing 'ACPI
        Private _Data As Byte() = Nothing


        Sub New(status_FrameError As Boolean, status_BitError As Boolean, status_ParityError As Boolean, _
                status_OverflowFlag As Boolean, status_LostFlag As Boolean, status_SequenceNr As Byte, _
                timeStamp As UInt16, repeatFlag As BusData.EIBBusData_FrameRepeatFlag, priority As BusData.EIBBusData_FramePriority, _
                destinationAddress As Addressing.EIBAddress, routing As Byte, tcpi As Byte, acpi As BusData.EIBBusData_FrameACPI_L_Data_Type, _
                data As Byte())

            MyBase.New(EIB.BusData.EIBBusData_EMICode.L_Busmon_ind)

            If status_SequenceNr > 7 Then Throw New ArgumentException("Sequence Number of Status must be <=7.")
            If Not [Enum].IsDefined(GetType(BusData.EIBBusData_FrameRepeatFlag), repeatFlag) Then Throw New ArgumentException("Repeat flag definition not valid.", "repeatFlag")
            If Not [Enum].IsDefined(GetType(BusData.EIBBusData_FramePriority), priority) Then Throw New ArgumentException("Priority definition not valid.", "priority")
            If destinationAddress.IsInvalid Then Throw New ArgumentException("Destination address not valid.", "destinationAddress")
            If routing > 7 Then Throw New ArgumentException("Routing count must be <= 7.", "routing")
            If Not [Enum].IsDefined(GetType(BusData.EIBBusData_FrameACPI_L_Data_Type), acpi) Then Throw New ArgumentException("")
            If data.Length < 1 Then Throw New ArgumentException("")

            _Status_FrameError = status_FrameError
            _Status_BitError = status_BitError
            _Status_ParityError = status_ParityError
            _Status_LostFlag = status_LostFlag
            _Status_OverflowFlag = status_OverflowFlag
            _Status_SequenceNr = status_SequenceNr
            _Status = (If(_Status_FrameError, 1, 0) << 7) + (If(_Status_BitError, 1, 0) << 6) + _
                     (If(_Status_ParityError, 1, 0) << 5) + (If(_Status_LostFlag, 1, 0) << 4) + _
                     (If(_Status_OverflowFlag, 1, 0) << 3) + (_Status_SequenceNr And &H7)

            _TimeStamp = timeStamp

            _RepeatFlag = repeatFlag
            _Priority = priority
            _Control = (1 << 7) + (_RepeatFlag << 5) + (1 << 4) + (_Priority << 2)

            _DestinationType = If(TypeOf destinationAddress Is Addressing.EIBPhysicalAddress, EIB.BusData.EIBBusData_FrameDestinationType.PhysicalAddress, EIB.BusData.EIBBusData_FrameDestinationType.GroupAddress)
            _Routing = routing
            _DataLength = data.Length
            _NCPI = (_DestinationType << 7) + (_Routing << 4) + _DataLength

            _SourceAddress = Addressing.EIBPhysicalAddress.Invalid
            _DestinationAddress = destinationAddress

            _TCPI = tcpi
            _ACPI = acpi


            Dim busdata As Byte() = New Byte(12 + _DataLength - 1) {}
            busdata(0) = _messageCode
            busdata(1) = _Status
            busdata(2) = (timeStamp And &HFF00) >> 8
            busdata(3) = (timeStamp And &HFF)
            busdata(4) = _Control
            busdata(5) = SourceAddress.ToByte()(0)
            busdata(6) = SourceAddress.ToByte()(1)
            busdata(7) = destinationAddress.ToByte()(0)
            busdata(8) = destinationAddress.ToByte()(1)
            busdata(9) = _NCPI
            busdata(10) = (_TCPI << 2) + ((_ACPI And &HC) >> 2)
            busdata(11) = ((_ACPI And &H3) << 6) + (data(0) And &H3F)

            For i = 1 To data.Length - 1
                busdata(11 + i) = data(i)
            Next

            busdata(busdata.Length - 1) = CalculateCheckSum(busdata)

            _busData = busdata
        End Sub

        Sub New(data As Byte())
            MyBase.New(data)

            If _messageCode <> EIB.BusData.EIBBusData_EMICode.L_Busmon_ind Then Throw New ArgumentException("This is not an 'L_BusMon'-frame.")
            If data.Length < 13 Then Throw New ArgumentException("Data must be at least 13 byte long for 'L_BusMon'.", "data")
            If CalculateCheckSum(data) <> data(data.Length - 1) Then Throw New EIB.Exceptions.EIBBusDataChecksumException("Checksum verification did not match.")

            _Status = data(1)
            _Status_FrameError = (_Status And &H80) >> 7
            _Status_BitError = (_Status And &H40) >> 6
            _Status_ParityError = (_Status And &H20) >> 5
            _Status_LostFlag = (_Status And &H10) >> 4
            _Status_OverflowFlag = (_Status And &H8) >> 3
            _Status_SequenceNr = (_Status And &H7)

            _TimeStamp = (CShort(data(2)) << 8) + data(3)

            _Control = data(4)
            ' 1
            ' 0
            _RepeatFlag = (_Control And &H20) >> 5
            ' 1
            _Priority = (_Control And &HC) >> 2
            ' 0
            ' 0

            _NCPI = data(9)
            _DestinationType = (_NCPI And &H80) >> 7
            _Routing = (_NCPI And &H70) >> 4
            _DataLength = (_NCPI And &HF)

            _SourceAddress = New Addressing.EIBPhysicalAddress(New Byte() {data(5), data(6)})
            _DestinationAddress = Addressing.EIBAddress.ParseAddress(New Byte() {data(7), data(8)}, _DestinationType)

            'data(6) and &HC0 muss "00" sein ?!
            _TCPI = (data(10) And &H3C) >> 2
            _ACPI = ((data(10) And &H3) << 2) + ((data(11) And &HC0) >> 6)

            If data.Length <> 12 + _DataLength Then Throw New EIB.Exceptions.EIBBusDataParseException("Data array size did not match containing data length.")

            _Data = New Byte(_DataLength - 1) {}
            _Data(0) = data(11) And &H3F
            For i = 1 To _DataLength - 1
                _Data(i) = data(11 + i)
            Next
        End Sub


        Public ReadOnly Property Status As Byte
            Get
                Return _Status
            End Get
        End Property

        Public ReadOnly Property Status_FrameError As Boolean
            Get
                Return _Status_FrameError
            End Get
        End Property

        Public ReadOnly Property Status_BitError As Boolean
            Get
                Return _Status_BitError
            End Get
        End Property

        Public ReadOnly Property Status_ParityError As Boolean
            Get
                Return _Status_ParityError
            End Get
        End Property

        Public ReadOnly Property Status_OverflowFlag As Boolean
            Get
                Return _Status_OverflowFlag
            End Get
        End Property

        Public ReadOnly Property Status_LostFlag As Boolean
            Get
                Return _Status_LostFlag
            End Get
        End Property

        Public ReadOnly Property Status_SequenceNr As Byte
            Get
                Return _Status_SequenceNr
            End Get
        End Property

        Public ReadOnly Property TimeStamp As UInt16
            Get
                Return _TimeStamp
            End Get
        End Property

        Public ReadOnly Property RepeatFlag As EIB.BusData.EIBBusData_FrameRepeatFlag
            Get
                Return _RepeatFlag
            End Get
        End Property

        Public ReadOnly Property Priority As EIB.BusData.EIBBusData_FramePriority
            Get
                Return _Priority
            End Get
        End Property

        Public ReadOnly Property SourceAddress As Addressing.EIBPhysicalAddress
            Get
                Return _SourceAddress
            End Get
        End Property

        Public ReadOnly Property DestinationAddress As Addressing.EIBAddress
            Get
                Return _DestinationAddress
            End Get
        End Property

        Public ReadOnly Property DestinationType As EIB.BusData.EIBBusData_FrameDestinationType
            Get
                Return _DestinationType
            End Get
        End Property

        Public ReadOnly Property Routing As Byte
            Get
                Return _Routing
            End Get
        End Property

        Public ReadOnly Property DataLength As Byte
            Get
                Return _DataLength
            End Get
        End Property

        Public ReadOnly Property NCPI As Byte
            Get
                Return _NCPI
            End Get
        End Property

        Public ReadOnly Property TCPI As Byte
            Get
                Return _TCPI
            End Get
        End Property

        Public ReadOnly Property ACPI As EIB.BusData.EIBBusData_FrameACPI_L_Data_Type
            Get
                Return _ACPI
            End Get
        End Property

        Public ReadOnly Property Data As Byte()
            Get
                Return _Data
            End Get
        End Property

        
        Public Overrides Function ToInfoList() As List(Of InfoBase)
            Dim list As New List(Of InfoBase)

            list.Add(New Info("EIB Message Code", String.Format("{0} (0x{0:X})", _messageCode)))
            Dim statusList As New List(Of InfoBase)
            list.Add(New InfoList("Status", String.Format("{0} (0x{0:X})", _Status), statusList))
            statusList.Add(New Info("Frame Error", _Status_FrameError))
            statusList.Add(New Info("Bit Error", _Status_BitError))
            statusList.Add(New Info("Parity Error", _Status_ParityError))
            statusList.Add(New Info("Overflow Flag", _Status_OverflowFlag))
            statusList.Add(New Info("Lost Flag", _Status_LostFlag))
            statusList.Add(New Info("Sequence #", _Status_SequenceNr))
            list.Add(New Info("Timestamp", _TimeStamp))
            Dim controlList As New List(Of InfoBase)
            list.Add(New InfoList("Control", String.Format("{0} (0x{0:X})", _Control), controlList))
            controlList.Add(New Info("Repeat Flag", String.Format("{0} (0x{0:X})", _RepeatFlag)))
            controlList.Add(New Info("Priority", String.Format("{0} (0x{0:X})", Priority)))
            list.Add(New Info("Source Adress", _SourceAddress.ToString()))
            list.Add(New Info("Dest. Adress", _DestinationAddress.ToString()))
            Dim ncpiList As New List(Of InfoBase)
            list.Add(New InfoList("NCPI", String.Format("{0} (0x{0:X})", _NCPI), ncpiList))
            ncpiList.Add(New Info("Dest. Type", String.Format("{0} (0x{0:X})", DestinationType)))
            ncpiList.Add(New Info("Routing", _Routing))
            ncpiList.Add(New Info("Data Length", _DataLength))
            list.Add(New Info("TCPI", String.Format("{0} (0x{0:X})", _TCPI)))
            list.Add(New Info("ACPI", String.Format("{0} (0x{0:X})", _ACPI)))
            Dim dataList As New List(Of InfoBase)
            list.Add(New InfoList("Data", "Byte[]", dataList))
            For i = 0 To _DataLength - 1
                dataList.Add(New Info(String.Format("Data {0}", i), _Data(i)))
            Next

            Return list
        End Function
    End Class
End Namespace